/*
 *  Copyright (C) 2010 Francesco Boffa (aka AlfaOmega08)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ImageFormats.Iso9660;

import ImageFormats.TreeElement;
import java.io.*;

public class IsoParser implements ImageFormats.ImageFormat {
	RandomAccessFile f = null;
	PrimaryVolumeDescriptor PVD = new PrimaryVolumeDescriptor();
	TreeElement Tree;
	String FileName;

	public void Init(String Path) throws Exception {
		FileName = Path;
		Parse();
	}

	public void Parse() throws Exception {
		f = new RandomAccessFile(FileName, "r");

		ParseVDs();
		BuildTree();
	}

	public void Shutdown() {
		try {
			f.close();
		} catch (IOException e) {
		}
	}

	private void SeekToSector(long sector) throws IOException {
		f.seek(sector * 2048);
	}

	private void ParseVDs() throws Exception {
		long sector = 16;
		Boolean Continue = true;

		do {
			SeekToSector(sector);

			byte type = -1;
			type = f.readByte();

			switch (type) {
				case 0:
					System.out.println("Found a boot vd");
					break;
				case 1:
					/* Restore alignement on the sector boundary */
					SeekToSector(sector);
					PVD.getFromStream(f);
					break;
				case 2:
					System.out.println("Found a supplementary vd");
					break;
				case 3:
					System.out.println("Found a partition vd");
					break;
				case -1:
					Continue = false;
					break;
				default:
					System.out.println("Invalid ISO Filesystem");
					System.exit(-1);
			}
			sector++;
		} while (Continue);
	}

	private void BuildTree() throws Exception {
		DirectoryRecord RootDirectory = PVD.getRootDirectoryRecord();

		Tree = new TreeElement("", Tree, true, true, RootDirectory.getSector(), RootDirectory.getSize());
		ParseDirectoryRecord(Tree, RootDirectory);
	}

	/*
	 * TODO: check how many entries we have to parse.
	 * Currently it stops the loop on some conditions, but I'm sure it can
	 * be done better.
	 */
	private void ParseDirectoryRecord(TreeElement parent, DirectoryRecord r) throws IOException {
		SeekToSector(r.getSector());
		int count = 0;
		int SizeRemainder = r.getSize();

		while (true) {
			DirectoryRecord nr = new DirectoryRecord();
			nr.getFromStream(f);
			if (nr.getStructureSize() == 0)
				break;
			if (SizeRemainder - nr.getStructureSize() < 0)
				break;

			long FpBackup = 0;
			FpBackup = f.getFilePointer();

			if (nr.isDirectory()) {
				TreeElement newDir = new TreeElement(nr.getName(), parent, true, false, nr.getSector(), nr.getSize());
				parent.AddChild(newDir);

				if (count > 1) {
					ParseDirectoryRecord(newDir, nr);
				}
			} else {
				String[] name = nr.getName().split(";");

				TreeElement newFile = new TreeElement(name[0], parent, false, false, nr.getSector(), nr.getSize());
				parent.AddChild(newFile);
			}

			f.seek(FpBackup);

			SizeRemainder -= nr.getStructureSize();

			count++;
		}
	}

	public TreeElement getNodeInfo(String Path) throws FileNotFoundException {
		Path = Path.trim();
		if (Path == null || Path.equals("")) {
			throw new FileNotFoundException("No such file or directory");
		}


		if (Path.equals(new String("/"))) {
			return Tree;
		}

		String[] RPath = Path.split("/");
		TreeElement tmp = Tree;

		for (int i = 1; i < RPath.length; i++) {
			tmp = tmp.getChild(RPath[i]);
		}

		return tmp;
	}

	public TreeElement[] getDirectoryContents(TreeElement dir) throws IOException {
		if (!dir.isDirectory()) {
			throw new IOException("Not a directory!!!");
		}

		java.util.Vector<TreeElement> c = dir.getChilds();
		TreeElement[] ret = new TreeElement[c.size()];

		for (int i = 0; i < c.size(); i++) {
			ret[i] = c.elementAt(i);
		}

		return ret;
	}

	public byte[] getFileContent(TreeElement File) throws IOException {
		return getFileContent(File, 0, -1);
	}

	public byte[] getFileContent(TreeElement File, int start, int length) throws IOException {
		int retSize = length == -1 ? File.getSize() : length;
		byte[] ret = new byte[retSize];

		SeekToSector(File.getDataSector());

		f.skipBytes(start);
		f.read(ret, 0, retSize);

		return ret;
	}
}
